package runner.PSO_VM;

import org.cloudbus.cloudsim.Vm;
import org.cloudbus.cloudsim.power.PowerHost;
import runner.jswarm_pso.Swarm;
import runner.utils.Calculator;
import runner.utils.Constants;

import java.util.ArrayList;
import java.util.List;


public class PSO {

    private static Swarm swarm;
    private static SchedulerParticle[] particles;
    private static SchedulerFitnessFunction ff;
    List<PowerHost> hostList = new ArrayList<>();
    List<Vm> vmList = new ArrayList<>();


    public PSO(List<Vm> vmList, List<PowerHost> hostList) {
        initParticles(vmList, hostList);
        ff = new SchedulerFitnessFunction(vmList, hostList);
        this.hostList = hostList;
        this.vmList = vmList;
    }

    public double[] run() {
        swarm = new Swarm(Constants1.POPULATION_SIZE, new SchedulerParticle(vmList, hostList), ff);

        double w_max = 1.2;
        double w_min = 0.4;
        swarm.setInertia(w_max);

        swarm.setMinPosition(0);
        swarm.setMaxPosition(hostList.size() - 1);
        swarm.setMaxMinVelocity(0.5);
        swarm.setParticles(particles);
        swarm.setParticleUpdate(new SchedulerParticleUpdate(new SchedulerParticle(vmList, hostList)));

        for (int i=0; i<Constants1.NO_OF_Iterations; i++) {
            /* 计算每个粒子的适应值
             *  更新每个粒子的速度和位置*/
            double w = swarm.getInertia();  // 获取当前惯性权值
            swarm.evolve();  // 算法正式的计算流程
            if (i % 10 == 0) {
                System.out.printf("Global best at iteration (%d): %f\n", i, swarm.getBestFitness());
            }
//            w = w_max - w_min*((i+1)/ Constants1.NO_OF_Iterations);
//            w = CalSOW(w_max, w_min, i, w);
            w=0.9;
            /* 另一种计算惯性权值的方法：在迭代过程中，将鲸鱼个体的适应度按升序排序，然后分成两半分别求平均适应度和，
             * 其中前半段适应度和 < 后半段适应度和，将当前鲸鱼个体的适应度分与两半段求得的适应度和比较，将惯性权重分类*/

            swarm.setInertia(w); // 设置惯性权值
        }
        System.out.printf("----------Global best at iteration: %f-----------\n", swarm.getBestFitness());
        //mapping = swarm.getBestPosition();
        /*for (int n=0; n<mapping.length; n++)
            vmhostMap.get(n).put(vmList.get(n).getUid(), hostList.get((int) mapping[n]));*/

        return swarm.getBestPosition();
    }

    /**
     * 根据迭代的次数计算自组织方式的惯性权重
     * @param w_max 权重上限
     * @param w_min 权重下限
     * @param i 当前迭代循环的中间变量 一般从0开始
     * @param w 惯性权重
     * @return 返回计算后的惯性权重值
     */
    private double CalSOW(double w_max, double w_min, int i, double w) {
        double iter = i+1;//当前迭代的次数
        double ret = Calculator.div(iter, Constants1.NO_OF_Iterations);
        if(iter>=1&iter<=Constants1.NO_OF_Iterations/2)
        {
            w= -Math.pow(ret,2.0)+w_max;
        }
        if(iter<=Constants1.NO_OF_Iterations && iter>Constants1.NO_OF_Iterations/2)
        {
            w= -Math.pow(ret-1.0,2.0)+w_min;
        }
        if(w>w_max)
        {
            w = w_max;
        }
        if(w<w_min)
        {
            w = w_min;
        }
        return w;
    }




    /** 初始化粒子
     * @param vmList
     * @param hostList*/
    private static void initParticles(List<Vm> vmList, List<PowerHost> hostList) {
        particles = new SchedulerParticle[Constants1.POPULATION_SIZE];  // 粒子个数50
        for (int i = 0; i < Constants1.POPULATION_SIZE; i++)
            particles[i] = new SchedulerParticle(vmList, hostList);
    }

}
